using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace FileEncoder
{
    public class FileEncoder
    {
        private string targetDir;
        private List<string> fileTypes;
        private bool isStopped;
        private int totalFiles;
        private int processedFiles;

        public event EventHandler<int> ProgressUpdated;
        public event EventHandler<string> LogMessage;
        public event EventHandler ConversionFinished;
        public event EventHandler<string> ConversionError;

        public FileEncoder()
        {
            fileTypes = new List<string>();
            isStopped = false;
        }

        public void SetTargetDir(string dir)
        {
            targetDir = dir;
        }

        public void SetFileTypes(List<string> types)
        {
            fileTypes = types;
        }

        public void StopConversion()
        {
            isStopped = true;
        }

        public void StartConversion()
        {
            try
            {
                isStopped = false;
                processedFiles = 0;
                totalFiles = 0;

                OnLogMessage("开始扫描文件夹: " + targetDir);

                if (!Directory.Exists(targetDir))
                {
                    OnConversionError("文件夹不存在: " + targetDir);
                    return;
                }

                List<string> allFiles = new List<string>();
                SearchFiles(targetDir, allFiles);

                if (isStopped)
                {
                    OnLogMessage("转换已取消");
                    OnConversionFinished();
                    return;
                }

                if (allFiles.Count == 0)
                {
                    OnLogMessage("未找到匹配的文件");
                    OnConversionFinished();
                    return;
                }

                totalFiles = allFiles.Count;
                OnLogMessage(string.Format("找到 {0} 个文件需要转换", totalFiles));

                foreach (string filePath in allFiles)
                {
                    if (isStopped)
                    {
                        OnLogMessage("转换已取消");
                        break;
                    }

                    ConvertFileToANSI(filePath);
                    processedFiles++;
                    int progress = (processedFiles * 100) / totalFiles;
                    OnProgressUpdated(progress);
                }

                OnLogMessage("转换完成");
                OnConversionFinished();
            }
            catch (Exception ex)
            {
                OnConversionError("转换失败: " + ex.Message);
            }
        }

        private void SearchFiles(string directory, List<string> files)
        {
            try
            {
                foreach (string fileType in fileTypes)
                {
                    string searchPattern = fileType.StartsWith("*.") ? fileType : "*."+fileType;
                    string[] matchingFiles = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly);
                    files.AddRange(matchingFiles);
                }

                string[] subDirectories = Directory.GetDirectories(directory);
                foreach (string subDir in subDirectories)
                {
                    if (isStopped) break;
                    SearchFiles(subDir, files);
                }
            }
            catch (UnauthorizedAccessException)
            {
                OnLogMessage("无法访问文件夹: " + directory);
            }
        }

        public string DetectAndReadFile(string filePath, out bool ok )
        {
            // 第一次读取：使用 StreamReader 自动检测编码
            Encoding detectedEncoding;
            string content = string.Empty ;
            ok = false;

            using (var reader = new StreamReader(filePath, Encoding.Default, true)) // 'true' 启用自动检测
            {                
                detectedEncoding = reader.CurrentEncoding;
                if (!detectedEncoding.Equals(Encoding.Default))
                {
                    content = reader.ReadToEnd();
                    ok = true ;
                }
            }

            // 检查检测到的编码
            Console.WriteLine($"检测到的编码: {detectedEncoding.EncodingName}");
            Console.WriteLine($"是否是 UTF-8: {detectedEncoding.Equals(Encoding.UTF8)}");
            Console.WriteLine($"是否是 UTF-8 BOM: {detectedEncoding.Equals(new UTF8Encoding(true))}");
            Console.WriteLine($"是否是 UTF-8 (无BOM): {detectedEncoding.Equals(new UTF8Encoding(false))}");

            return content;
        }


        private void ConvertFileToANSI(string filePath)
        {
            try
            {
                if (!IsTextFile(filePath))
                {
                    OnLogMessage(string.Format("跳过非文本文件: {0}", filePath));
                    return;
                }
                bool needConvert;
                //DetectAndReadFile(filePath,out needConvert);
                ;
                if (!IsFileUtf8Encoded(filePath) )
                {
                    string content = File.ReadAllText(filePath, Encoding.UTF8);

                    File.WriteAllText(filePath, content, Encoding.Default);

                    OnLogMessage(string.Format("已转换: {0}", filePath));
                }
                else {
                    OnLogMessage(string.Format("无需转换: {0}", filePath));
                }
            }
            catch (Exception ex)
            {
                OnLogMessage(string.Format("转换失败: {0} - {1}", filePath, ex.Message));
            }
        }

        private bool IsTextFile(string filePath)
        {
            try
            {
                byte[] buffer = new byte[1024];
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    int bytesRead = fs.Read(buffer, 0, Math.Min(1024, (int)fs.Length));
                    for (int i = 0; i < bytesRead; i++)
                    {
                        if (buffer[i] == 0)
                        {
                            return false;
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        protected virtual void OnProgressUpdated(int progress)
        {
            ProgressUpdated?.Invoke(this, progress);
        }

        protected virtual void OnLogMessage(string message)
        {
            LogMessage?.Invoke(this, message);
        }

        protected virtual void OnConversionFinished()
        {
            ConversionFinished?.Invoke(this, EventArgs.Empty);
        }

        protected virtual void OnConversionError(string error)
        {
            ConversionError?.Invoke(this, error);
        }

        /// <summary>
        /// 读取文件并检测编码，特别关注 UTF-8 检测
        /// </summary>
        public static (string Content, Encoding Encoding, bool IsUtf8, bool HasBom) ReadFileWithEncodingInfo(string filePath)
        {
            byte[] fileBytes = File.ReadAllBytes(filePath);

            // 1. 检查 BOM (字节顺序标记)
            Encoding encoding = DetectEncodingFromBom(fileBytes);
            bool hasBom = encoding != null;

            // 2. 如果没有检测到 BOM，尝试自动检测
            if (encoding == null)
            {
                encoding = DetectEncodingWithoutBom(fileBytes);
            }

            // 3. 读取内容
            string content;
            if (hasBom && encoding is UTF8Encoding)
            {
                // 对于带BOM的UTF-8，跳过前3个字节
                content = Encoding.UTF8.GetString(fileBytes, 3, fileBytes.Length - 3);
            }
            else
            {
                content = encoding.GetString(fileBytes);
            }

            // 4. 检查是否是 UTF-8
            bool isUtf8 = encoding is UTF8Encoding ||
                          encoding.Equals(Encoding.UTF8) ||
                          encoding.EncodingName.Contains("UTF-8");

            return (content, encoding, isUtf8, hasBom);
        }

        /// <summary>
        /// 通过 BOM 检测编码
        /// </summary>
        private static Encoding DetectEncodingFromBom(byte[] bytes)
        {
            if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
                return Encoding.UTF8; // UTF-8 with BOM

            if (bytes.Length >= 2 && bytes[0] == 0xFE && bytes[1] == 0xFF)
                return Encoding.BigEndianUnicode; // UTF-16 BE

            if (bytes.Length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xFE)
                return Encoding.Unicode; // UTF-16 LE

            if (bytes.Length >= 4 && bytes[0] == 0x00 && bytes[1] == 0x00 &&
                bytes[2] == 0xFE && bytes[3] == 0xFF)
                return Encoding.UTF32; // UTF-32 BE

            return null; // 没有检测到 BOM
        }

        /// <summary>
        /// 在没有 BOM 的情况下检测编码
        /// </summary>
        private static Encoding DetectEncodingWithoutBom(byte[] bytes)
        {
            try
            {
                // 使用 StreamReader 自动检测
                using (var stream = new MemoryStream(bytes))
                using (var reader = new StreamReader(stream, Encoding.Default, true, 1024, true))
                {
                    reader.ReadToEnd(); // 必须读取才能触发编码检测
                    return reader.CurrentEncoding;
                }
            }
            catch
            {
                // 如果自动检测失败，回退到系统默认编码
                return Encoding.Default;
            }
        }

        /// <summary>
        /// 检查文件是否是 UTF-8 编码
        /// </summary>
        public static bool IsFileUtf8Encoded(string filePath)
        {
            var result = ReadFileWithEncodingInfo(filePath);
            return result.IsUtf8;
        }
    }
}
